from sqlalchemy.exc import SQLAlchemyError
from app.utils.logger_util import LoggerUtil


class MySQLTool:
    _instance = None

    @classmethod
    def get_instance(cls, db=None):
        """
        获取 MySQLTool 的单例实例。

        :param db: SQLAlchemy 数据库实例
        :return: MySQLTool 实例
        """
        if cls._instance is None:
            cls._instance = cls(db)
            cls._instance.logger.info(f"MySQLTool调度器初始化成功 实例ID:{id(cls._instance)}")
        return cls._instance

    def __init__(self, db):
        """
        初始化 MySQLTool 实例。

        :param db: SQLAlchemy 数据库实例
        """
        self.db = db
        self.logger = LoggerUtil.get_logger()

    def add_data(self, data):
        """
        向数据库中添加数据。

        :param data: SQLAlchemy 模型实例
        :return: None
        """
        try:
            self.db.session.add(data)
            self.db.session.commit()
        except SQLAlchemyError as e:
            self.db.session.rollback()
            self.logger.error(f"Error adding data: {e}")

    def update_data(self, model, filter_obj, update_obj):
        """
        根据条件更新数据库中的数据。

        :param model: SQLAlchemy 模型类
        :param filter_obj: SQLAlchemy 模型实例，用于过滤条件
        :param update_obj: SQLAlchemy 模型实例，其属性值将更新到匹配的记录中
        :return: 更新后的记录或 None
        """
        try:
            # 确保 filter_obj 和 update_obj 是 SQLAlchemy 模型实例
            if not hasattr(filter_obj, '_sa_instance_state') or not hasattr(update_obj, '_sa_instance_state'):
                raise ValueError("filter_obj and update_obj must be SQLAlchemy model instances")

            # 构建过滤条件字典，排除空值
            filter_dict = {key: getattr(filter_obj, key) for key in filter_obj.__dict__ if
                           not key.startswith('_') and getattr(filter_obj, key) is not None}

            # 使用过滤条件查询记录
            record = self.db.session.query(model).filter_by(**filter_dict).first()
            if record:
                # 更新记录的属性
                for key in update_obj.__dict__:
                    if not key.startswith('_') and getattr(update_obj, key) is not None:
                        setattr(record, key, getattr(update_obj, key))
                self.db.session.commit()
            return record
        except (SQLAlchemyError, ValueError) as e:
            self.db.session.rollback()
            self.logger.error(f"Error updating data: {e}")
            return None

    def delete_data(self, model, **filters):
        """
        根据给定的条件删除数据库中的数据。

        :param model: SQLAlchemy 模型类
        :param filters: 过滤条件，以字典形式传递，例如 {'id': 1}
        :return: 删除的记录数量
        """
        try:
            records = self.db.session.query(model).filter_by(**filters).all()
            for record in records:
                self.db.session.delete(record)
            self.db.session.commit()
            return len(records)
        except SQLAlchemyError as e:
            self.db.session.rollback()
            self.logger.error(f"Error deleting data: {e}")
            return 0

    def query_data(self, model, **filters):
        """
        根据给定的模型和过滤条件查询数据。

        :param model: SQLAlchemy 模型类
        :param filters: 过滤条件，以字典形式传递，例如 {'username': 'test'}
        :return: 查询结果列表
        """
        try:
            return self.db.session.query(model).filter_by(**filters).all()
        except SQLAlchemyError as e:
            self.logger.error(f"Error querying data: {e}")
            return []

    def execute_custom_sql(self, sql, params=None):
        """
        执行自定义的 SQL 语句，可以带参数（可选）。

        :param sql: 要执行的 SQL 语句字符串
        :param params: SQL 语句中的参数（如果有），以字典形式传递，例如 {"name": "John"}
        :return: 查询结果或受影响的行数
        """
        try:
            connection = self.db.engine.connect()
            if params:
                result_proxy = connection.execute(sql, params)
            else:
                result_proxy = connection.execute(sql)
            if sql.strip().lower().startswith('select'):
                result = result_proxy.fetchall()
                return result
            else:
                connection.commit()
                return result_proxy.rowcount
        except SQLAlchemyError as e:
            self.logger.error(f"执行 SQL 语句出错: {e}")
            return None
        finally:
            connection.close()
